package com.bookmanager.www.controller.oauth2;

import com.alibaba.fastjson.JSONObject;
import com.bookmanager.www.common.cache.AuthStateRedisCache;
import com.bookmanager.www.common.utils.JwtUtil;
import com.bookmanager.www.common.utils.LoginUserUtils;
import com.bookmanager.www.common.utils.Result;
import com.bookmanager.www.common.utils.ShiroUtils;

import com.bookmanager.www.entity.FlUser;
import com.bookmanager.www.mapper.FlUserMapper;
import com.bookmanager.www.service.FlUserService;

import com.xkcoding.http.config.HttpConfig;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import kohgylw.kcnamer.core.KCNamer;
import lombok.extern.slf4j.Slf4j;

import me.zhyd.oauth.config.AuthConfig;
import me.zhyd.oauth.enums.scope.*;
import me.zhyd.oauth.exception.AuthException;
import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.model.AuthResponse;
import me.zhyd.oauth.model.AuthToken;
import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.request.*;

import me.zhyd.oauth.utils.AuthScopeUtils;
import me.zhyd.oauth.utils.AuthStateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

import java.net.InetSocketAddress;
import java.net.Proxy;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author 风离
 */
@Slf4j
@Controller
@RequestMapping("/oauth2")
@Api(tags = "第三方登录/注册/绑定/解绑")
public class RestAuthController {

    @Resource
    private AuthStateRedisCache stateRedisCache;
    @Resource
    private FlUserMapper flUserMapper;
    @Resource
    private FlUserService flUserService;

    /**
     *  设置为全局变量
     */
    private static String user_id;

    private final static String base = "http://localhost:8080/#/index?code=";

    private final static String base2 = "http://localhost:8080/#/userhome/shezhi";


    @GetMapping("/render/{source}/{userId}")
    @ResponseBody
    @ApiOperation(value = "请求绑定第三方")
    public void bindOAuth(@PathVariable("source") String source,@PathVariable("userId") String userId, HttpServletResponse response) throws IOException {
        user_id = userId;
        log.info("进入render：" + source);
        AuthRequest authRequest = getAuthRequest(source);
        String authorizeUrl = authRequest.authorize(AuthStateUtils.createState());
        log.info(authorizeUrl);
        response.sendRedirect(authorizeUrl);
    }


    @GetMapping("/render/{source}")
    @ResponseBody
    @ApiOperation(value = "请求第三方登录系统",notes = "传入地址参数 gitee 或者qq 或者 weibo")
    /**
     * 整合第三方登录流程:
     * 1. 首先应该是进入系统之后在个人用户中心绑定对应的第三方账号 (gitee...）
     * 2. 绑定之后用户点击相应的第三方登录按钮 即可登录到对应的第三方账号
     * 3. 快捷方式 注册的时候 获取第三方登录的用户信息 并由此生成用户账号 头像 密码... (登录进去之后个人中心默认已经绑定该账号)
     *
     */
    public void renderAuth(@PathVariable("source") String source, HttpServletResponse response) throws IOException {
        log.info("进入render：" + source);
        AuthRequest authRequest = getAuthRequest(source);
        String authorizeUrl = authRequest.authorize(AuthStateUtils.createState());
        log.info(authorizeUrl);
        response.sendRedirect(authorizeUrl);
    }

    /**
     * oauth平台中配置的授权回调地址，以本项目为例，在创建github授权应用时的回调地址应为：http://127.0.0.1:8443/oauth/callback/github
     * 如果这个返回链接需要token 那么直接就进不来了
     * 如果这个链接不需要token 就获取不到用户的id信息了
     */
    @GetMapping("/callback/{source}")
    public void login(@PathVariable("source") String source, AuthCallback callback,
                        HttpServletRequest request,HttpServletResponse resp) throws IOException {
        log.info("进入callback：" + source + " callback params：" + JSONObject.toJSONString(callback));
        AuthRequest authRequest = getAuthRequest(source);
        AuthResponse<AuthUser> response = authRequest.login(callback);
        log.info(JSONObject.toJSONString(response));

        if (response.ok()) {
            //这里保存返回回来的用户数据
            AuthUser authUser = response.getData();
            String uuid = authUser.getUuid();
            String accessToken  =authUser.getToken().getAccessToken();

            /**
             *如果这个用户id已被某个用户关联直接返回该用户的信息 登录到用户中心
             * 如果这个id没有被 任何用户关联 就 这里有两个选择 绑定已有账号信息 以这个第三方账号新建用户信息
             *         1新建个用户 并登录进用户中心
             *         2在用户中心绑定
             */
            String userId = flUserMapper.selectUserIdByOAuth2UuidAndType(uuid,source);
            if(userId!=null)
            {
                String jwt = LoginUserUtils.getJWT(userId);
//                // 取消授权试试
//                Object test = authRequest.revoke(AuthToken.builder().accessToken(accessToken).build());
//                log.info("取消授权日志---"+test);
                resp.sendRedirect(base+jwt);
            }else {
                if(user_id!=null)
                {
                    //已经登录进系统了 所以应该是绑定第三方账号的操作
                    String myUserId = ShiroUtils.getUserId();
                    int insert = flUserMapper.insertOAuth2User(uuid,myUserId,source,accessToken);
                    log.info("是否绑定第三方账号成功？？"+insert);
//                    // 取消授权试试
//                    Object test = authRequest.revoke(AuthToken.builder().accessToken(accessToken).build());
//                    log.info("取消授权日志---"+test);
                    resp.sendRedirect(base2);

                }
                //你都登录进系统了还注册个鸡毛~~
                //用获取到的第三方信息注册用户
                String username = authUser.getNickname();
                FlUser flUser1 = flUserMapper.selectUserByUsername(username);
                if(flUser1!=null)
                {
                    //本地数据库中存在同名情况  重新给他一个随机姓名
                    username =new KCNamer().getRandomName();
                }

                //默认初始密码123456 登录进去之后可修改
                String password = "123456";
                String avatar = authUser.getAvatar();
                FlUser flUser = flUserService.registerUserByOAuth2(username,password,avatar,uuid,source,accessToken);
                String jwt =LoginUserUtils.getJWT(flUser.getUserId());
//                // 取消授权试试
//                Object test = authRequest.revoke(AuthToken.builder().accessToken(accessToken).build());
//                log.info("取消授权日志---"+test);
                resp.sendRedirect(base+jwt);

            }

        }
        Map<String, Object> map = new HashMap<>(1);
        map.put("errorMsg", response.getMsg());

//        return Result.fail("第三方校验失败！！请选择其他登录方式",map);
    }




    /**
     * 根据具体的授权来源，获取授权请求工具类
     *
     * @param source
     * @return
     */
    private AuthRequest getAuthRequest(String source) {
        AuthRequest authRequest = null;
        switch (source.toLowerCase()) {
            case "github":
                authRequest = new AuthGithubRequest(AuthConfig.builder()
                        .clientId("5b0b5100d82958842516")
                        .clientSecret("511add509a83506fd8b20915eabe5fcd38ec1780")
                        .redirectUri("http://localhost:8081/oauth2/callback/github")
                        .scopes(AuthScopeUtils.getScopes(AuthGithubScope.values()))
//                        // 针对国外平台配置代理
                        .httpConfig(HttpConfig.builder()
                                .timeout(15000)
                                .proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 10809)))
                                .build())
                        .build(), stateRedisCache);
                break;

            case "baidu":
                authRequest = new AuthBaiduRequest(AuthConfig.builder()
                        .clientId("yGOF1ElywTR69FCQj3ScNAHi")
                        .clientSecret("yyiOGT4GqkEwSwrP97qhdOXcBiTqanXr")
                        .redirectUri("http://localhost:8081/oauth2/callback/baidu")
                        .scopes(Arrays.asList(
                                AuthBaiduScope.BASIC.getScope(),
                                AuthBaiduScope.SUPER_MSG.getScope(),
                                AuthBaiduScope.NETDISK.getScope()
                        ))
                        .build());
                break;
            case "gitee":
                authRequest = new AuthGiteeRequest(AuthConfig.builder()
                        .clientId("44c6f1c72f8dfcf65137660d75e1582ebfc52c1192ed40c76721378699407bd8")
                        .clientSecret("2dfc822089f8abd35040431074c3b5e1e458642a8e845e0383556beef8278ecd")
                        .redirectUri("http://localhost:8081/oauth2/callback/gitee")
//                        .scopes(AuthScopeUtils.getScopes(AuthGiteeScope.values()))
                        .build(), stateRedisCache);
                break;
            case "weibo":
                authRequest = new AuthWeiboRequest(AuthConfig.builder()
                        .clientId("")
                        .clientSecret("")
                        .redirectUri("http://dblog-web.zhyd.me/oauth/callback/weibo")
                        .scopes(Arrays.asList(
                                AuthWeiboScope.EMAIL.getScope(),
                                AuthWeiboScope.FRIENDSHIPS_GROUPS_READ.getScope(),
                                AuthWeiboScope.STATUSES_TO_ME_READ.getScope()
                        ))
                        .build());
                break;

            case "qq":
                authRequest = new AuthQqRequest(AuthConfig.builder()
                        .clientId("")
                        .clientSecret("")
                        .redirectUri("http://localhost:8443/oauth/callback/qq")
                        .build());
                break;

            default:
                break;
        }
        if (null == authRequest) {
            throw new AuthException("未获取到有效的Auth配置");
        }
        return authRequest;
    }
}
